var $ = window.$;
var event = require('../../core/event');
var vector = require('./vector');
var timer = require('../../core/timer');
var sample = require('../sample/manager');
var layer = require('../layer/manager');
var notify = require('../notify/ui');
var frac = require('../../util/frac');
var Log = require('../../util/logger');
var util = require('../../util/index');
var input = require('../../core/input');
var jade = require('jade');
var sound = require('../audio/sound');
var gridUtil = require('./util');
var timing = require('../timing/manager');
var base = require('./ui.js');
var inherits = require('util').inherits;
var record = require('../../core/record');
var config = require('../../core/config');

var GridUICatch = function () {

};

inherits(GridUICatch, base);
GridUICatch.prototype._cancelSelect = base.prototype.cancelSelect;
GridUICatch.prototype._onMouseDown = base.prototype.onMouseDown;
GridUICatch.prototype._deleteNote = base.prototype.deleteNote;
GridUICatch.prototype._updateNotes = base.prototype.updateNotes;
GridUICatch.prototype._deleteSelect = base.prototype.deleteSelect;

GridUICatch.prototype.init = function () {
    if (this._inited) {
        return;
    }
    var self = this;

    this._beatH = 150;
    this._noteH = 30;  // 跟css里关联
    this._verticalLine = 0;
    this._gridBtY = 100;
    this._gridPadding = 75;
    this.TYPE_RAIN = 3;

    this.parent = $('#edit_up');
    var tmpl = jade.compileFile('./tmpl/grid/catch.jade');
    this.parent.html(tmpl());

    this.editArea = $('#edit_area');
    this.grid = $('#grid');
    this.note = $('#note_area');
    this.line = $('#grid_line');
    this.currline = null;
    this.select = $('#select_area');
    this.tip = $('#note_tip');
    this.range = $('#range');
    this.vert = $('#note_vert');

    //this.pluginSelect = require('./plugin/select-catch');
    //this.pluginSelect.setUI(this);

    var plugin = require('./plugin/edit-catch');
    this.pluginEdit = new plugin();
    this.pluginEdit.setUI(this);
    this.pluginCopy = require('./plugin/copy-catch');
    this.pluginCopy.setUI(this);
    this.pluginUndo = require('./plugin/undo');
    this.pluginUndo.init();
    this.pluginUndo.setUI(this);
    plugin = require("./plugin/meta");
    this.pluginMeta = new plugin();
    this.pluginMeta.init();
    this.pluginMeta.setUI(this);
    this.record = record;
    record.init();
    this.focus = false;
    this.hover = false;
    this.playId = -1;
    this.totalW = this.parent.width();
    this.scaleW = this.grid.find('.note').width() / 512;  //为什么是512, 因为osu用了这个值, 也比较合理, 没有改动的必要
    this._noteH = 40;
    //this.catchW = 96 * this.scaleW;
    this.bind();

    this.isMouseDown = false;
    this.noteAreaY = 0;  //note area 下边的偏移值
    this.gridScale = 1.0;  //1 beat的缩放值
    this.gridScaleH = this._beatH * this.gridScale;  //这两个要联动
    this.gridH = this.grid.height();
    this.divide = 4;
    this.lastUpdate = 0;
    this.needUpdate = false;
    this.selectScroll = 0;   //鼠标按下状态, 且位于grid上下边缘时, 有个时间seek附属效果
    this.fastSeekTime = NaN;
    this.seekTimer = null;
    timing.init();

    //this.updateGrid();
    //this.updateVerticalGrid();
    this.bindToolEvents();
    this._inited = true;
};

GridUICatch.prototype.bindToolEvents = function () {
    var self = this;
    $("#tool_rain,#tool_hold,#tool_normal").on('click', function (e) {
        var tool = $(this);
        var id = tool.attr("id");
        if(id == "tool_hold"){
            self.showBlurMsg(util.formatStr(config.i18n("catch02"), [self.pluginEdit.MAX_HOLD_NOTES]));
        }else if(id == "tool_rain"){
            self.showBlurMsg(config.i18n("catch01"));
        }
        self.pluginEdit.endHoldRainDrawing();
    });
};

/**
 * 强制同步全部note
 * 目前只有第一次加载note需要调用
 */
GridUICatch.prototype.sync = function () {
    this.note.html('');

    var notes = this.manager.getNotes();
    if (!notes) {
        return;
    }
    var info = this.manager.getEditInfo();
    if (info.grid) {
        //重置可编辑区域长度
        if (info.grid.length) {
            sound.setMaxLength(info.grid.length);
        } else {
            sound.setMaxLength(60000);
        }
        if (info.grid.vertical) {
            this._verticalLine = info.grid.vertical;
        }
    }

    this.divide = gridUtil.clampDivide(config.getVal(config.ITEM.GRID_DIVI) || 4);
    this.gridScale = config.getVal(config.ITEM.GRID_ZOOM) || 1;
    this.gridScaleH = this.gridScale * this._beatH;

    var htmls = [];
    for (var i = 0; i < notes.length; i++) {
        var note = notes[i];
        var html = this.makeNoteDiv(note);
        htmls.push(html);
    }
    htmls.push(this.getCatchNotesDiv());
    this.note.append(htmls.join(''));

    this.updateGrid();
    this.updateVerticalGrid();
    if (info.grid && info.grid.referVert) {
        this.updateReferLine(info.grid.referVert);
    }
    this.needUpdate = true;
    this.onUpdate();
    //完全同步时, 自动获得焦点
    if (!this.focus) {
        this.focus = true;
        event.trigger(event.events.global.blur, null, this);
    }

};

GridUICatch.prototype.updateNotes = function (param) {
    this._updateNotes(param);
    this.note.children(".hold_line").remove();
    this.note.append(this.getCatchNotesDiv());
};

GridUICatch.prototype.deleteSelect = function () {
    //在批量删除之前依次删除hold和rain 并改变连接线的位置
    var notes = this.note.children(".hold_node.curr,.spinner_anchor.curr");
    while (notes.length) {
        this.deleteNote(this.manager.getNote(notes.first().attr("data-tag")));
        notes = this.note.children(".hold_node.curr,.spinner_anchor.curr");
    }
    this._deleteSelect();
};

GridUICatch.prototype.getCatchNotesDiv = function () {
    var notes = this.manager.getNotes();
    var s = "";
    for (var i = 0; i < notes.length; i++) {
        var note = notes[i];
        if (!note._endbeat) {
            continue;
        }
        var endNote = {
            beat: note._endbeat,
            x: note.endx,
            prev: note.id
        };
        if (note.type == this.TYPE_RAIN) {
            s += this.getSpinnerMaskDiv(note, endNote);
        } else {
            s += this.getNoteHoldLineDiv(note, endNote);
        }
    }
    return s;
};

GridUICatch.prototype.getSpinnerMaskDiv = function (startNote, endNote, isUpdate) {
    var y1 = this.gridToLayerY(startNote.beat);
    var y2 = this.gridToLayerY(endNote.beat);
    var h = y2 - y1;
    if (isUpdate) {
        this.note.children(".spinner_mask[data-prev-id='" + startNote.id + "']").css({
            bottom: y1 + "px",
            height: h + "px"
        });
    } else {
        return '<span class="spinner_mask" style="bottom:' + y1 + 'px;height:' + h + 'px;" data-prev-id="' + startNote.id + '"></span>';
    }
};

GridUICatch.prototype.onMouseDown = function (e) {
    //如果是在绘制hold点的时候按右键 则取消绘制 此时没有删除动作
    if(e.which == 3 && this.pluginEdit.lastNote){
        this.pluginEdit.endStepEdit();
        return;
    }
    this._onMouseDown(e);
    if (e.which == 3) {
        this.pluginEdit.checkSelectTip();
    }
};

GridUICatch.prototype.beforeDelHoldNote = function (note) {
    if (!(note.prev > 0 || note.next > 0 )) {
        return;
    }
    if (note.type == this.TYPE_RAIN) {
        return;
    }
    var prevNote, nextNote;
    if (note.next == -1 || !note.next) {
        //删除最后一个元素
        prevNote = this.manager.getNote(note.prev);
        prevNote.next = -1;
    } else if (note.prev == -1 || !note.prev) {
        //删除第一个元素
        prevNote = note;
        nextNote = this.manager.getNote(note.next);
        nextNote.prev = -1;
    } else {
        //删除任意一个元素
        nextNote = this.manager.getNote(note.next);
        prevNote = this.manager.getNote(note.prev);
        nextNote.prev = prevNote.id;
        prevNote.next = nextNote.id;
    }
    //删除两个note之间的连接线
    this.note.children(".hold_line[data-prev-id='" + prevNote.id + "']").remove();
    if (note.next > 0 && note.prev > 0) {
        this.note.children(".hold_line[data-prev-id='" + note.id + "']").remove();
        //重建两个note之间的连接线
        this.note.append(this.getNoteHoldLineDiv(prevNote, nextNote));
    }
};

GridUICatch.prototype.deleteNote = function (note) {
    this.beforeDelHoldNote(note);
    this.beforeDelSpinnerNote(note);
    this._deleteNote(note);
};

GridUICatch.prototype.beforeDelSpinnerNote = function (note) {
    //删除spinner的另一个note和连接线
    var prev, toDel;
    if (note.type != this.TYPE_RAIN) {
        return;
    }
    if (note.next > 0) {
        toDel = this.manager.getNote(note.next);
        prev = note;
    } else if (note.prev > 0) {
        toDel = this.manager.getNote(note.prev);
        prev = toDel;
    }
    this.note.find(".spinner_mask[data-prev-id='" + prev.id + "']").remove();
    this._deleteNote(toDel);
};

GridUICatch.prototype.updateGridConfig = function () {
    //仅当scale变化时才需要重置note
    //其他情况只改节拍线
    var param = util.getJsonChainValue(this.manager.chart, "extra.grid") || {};
    var _divide = config.getVal(config.ITEM.GRID_DIVI) || 4;
    var _zoom = config.getVal(config.ITEM.GRID_ZOOM) || 1;
    var changed = false;
    if (_zoom != this.gridScale) {
        this.gridScale = _zoom;
        this.gridScaleH = this.gridScale * this._beatH;
        this.updateNotes();
        changed = true;
    }
    if (_divide != this.divide) {
        this.divide = _divide;
        changed = true;
    }
    if (changed) {
        this.updateGrid();
    }
    if (param.vertical && param.vertical != this._verticalLine) {
        this._verticalLine = param.vertical;
        this.updateVerticalGrid();
    }
    if (param.referVert) {
        this.updateReferLine(param.referVert);
    }
};

GridUICatch.prototype.updateVerticalGrid = function () {
    var area = this.grid.find('.note');
    area.html('');
    if (this._verticalLine < 2) {
        return;
    }
    var htmls = [];
    for (var i = 1; i < this._verticalLine; i++) {
        var html = '<i style="left:' + (i * 100 / this._verticalLine) + '%;"></i>';
        htmls.push(html);
    }
    area.append(htmls.join(''));
};

GridUICatch.prototype.updateReferLine = function (arr) {
    var area = this.grid.find('.note');
    area.find('i.re').remove();

    var htmls = [];
    for (var i = 0; i < arr.length; i++) {
        var html = '<i class="re" style="left:' + arr[i] + '%;"></i>';
        htmls.push(html);
    }
    area.append(htmls.join(''));
};

GridUICatch.prototype.cancelSelect = function () {
    this._cancelSelect();
    this.range.hide();
    this.vert.hide();
};

/**
 * 辅助方法
 */

GridUICatch.prototype.alignNote = function (note, div) {
    var y = this.gridToLayerY(note.beat);
    var conf = {
        bottom: y
    };
    conf.left = note.x * this.scaleW;
    if (note.endbeat) {

    } else {
        conf.height = this._noteH;
    }
    div.css(conf);
};

GridUICatch.prototype.makeNoteDiv = function (note) {
    var y = this.gridToLayerY(note.beat);
    var x = note.x * this.scaleW;
    var style = 'left:' + x + 'px;bottom:' + y + 'px';
    if (typeof note.color == 'number') {
        var _color = layer.getColor(note.color);
        if (_color) {
            style += ';background-color:' + _color;
        }
    }
    var cls = "";
    var tag = ' data-tag="' + note.id + '"';
    if (note.isBgm) {
        //style += ";display:none";
        cls = ' class="bgm-note" ';
    }
    else if (note.type == this.TYPE_RAIN) {
        //style += ";display:none";
        cls = ' class="spinner_anchor" ';
    }
    else if (note.prev > 0 || note.next > 0) {
        cls = ' class="hold_node" ';
    }
    return '<div ' + cls + ' style="' + style + '"' + tag + '></div>';
};

GridUICatch.prototype.getNoteHoldLineDiv = function (startNote, endNote, isUpdate) {
    var x1 = startNote.x * this.scaleW;
    var y1 = this.gridToLayerY(startNote.beat);
    var x2 = endNote.x * this.scaleW;
    var y2 = this.gridToLayerY(endNote.beat);
    var dy = y2 - y1;
    var dx = x2 - x1;
    var _len = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));//用于计算三角函数的线长
    var len = _len - this._noteH - 4; //旋转后的线长
    var theta = Math.atan(dy / dx) / Math.PI * -180;//换算成角度
    if (x2 < x1) {
        theta = theta + 180;
    }
    var sinTheta = dy / _len;
    var cosTheta = dx / _len;
    var px = x1 + this._noteH / 2 + this._noteH / 2 * cosTheta - 2;
    var py = y1 + this._noteH / 2 + this._noteH / 2 * sinTheta;
    //这里不能用div 否则刷新的时候拿所有div要报错
    if (isUpdate) {
        this.note.children(".hold_line[data-prev-id='" + startNote.id + "']").css({
            width: len,
            bottom: py + "px",
            left: px + "px",
            "-webkit-transform": "rotate(" + theta + "deg)"
        });
    }
    var lineHtm = '<span class="hold_line" data-prev-id="' + startNote.id + '" style="width:' + len + 'px;-webkit-transform:rotate(' + theta + 'deg);bottom:' + py + 'px;left:' + px + 'px"></span>';
    return lineHtm;
};

GridUICatch.prototype.updateRange = function (normal) {
    this.range.find('.normal').css('width', normal);
    this.range.find('.dash').css('width', normal);
    this.range.css('marginLeft', -normal * 1.5 + 80);  //fixme 80是hack, 等于css中左边留白的距离
};

GridUICatch.prototype.mirrorFlip = function () {
    var notes = this.manager.getSelectNotes();
    for (var i = 0; i < notes.length; i++) {
        var mirNote = util.cloneObject(notes[i]);
        mirNote.x = 512 - mirNote.x;
        this.manager.addNote(mirNote);
        var noteDiv = this.pluginEdit.addNoteDiv(mirNote);
        this.alignNote(mirNote, noteDiv);
    }
};

GridUICatch.prototype.flipNotes = function () {
    var div = this.note.find('.curr');
    var note = [];
    var len = div.size();
    if (len == 0) {
        return;
    }

    //最大最小column
    var min = 9999999;
    var max = -1;
    for (var i = 0; i < len; i++) {
        var id = +div.eq(i).data('tag');
        var _note = this.manager.getNote(id);
        note.push(_note);
        if (_note.x > max) {
            max = _note.x;
        }
        if (_note.x < min) {
            min = _note.x;
        }
    }
    if (max == min) {
        return;
    }
    for (var i = 0; i < len; i++) {
        var _note = note[i];
        _note.x = max + min - _note.x;
        this.alignNote(_note, div.eq(i));
    }
    event.trigger(event.events.note.change);
};

/**
 * 画布的x坐标映射到512栅格空间, 考虑当前栅格对齐
 * @param _x
 * @returns {number}
 */
GridUICatch.prototype.mouseToX = function (_x) {
    _x = Math.floor((_x + 2) / this.scaleW);
    if (this._verticalLine > 1) {
        var divi = 512 / this._verticalLine;
        _x = Math.round(Math.round(_x / divi) * divi);
    }
    return _x;
};

/**
 * 将X对齐到当前栅格
 * 非512坐标系
 * @param _x
 */
GridUICatch.prototype.alignToX = function (_x) {
    if (this._verticalLine > 1) {
        var divi = 512 * this.scaleW / this._verticalLine;
        _x = Math.round(_x / divi) * divi;
    }
    return _x;
};

/**
 * 画布坐标映射到栅格坐标，到最近的栅格
 * @param param
 */
GridUICatch.prototype.layerToGrid = function (param) {
    var beat = frac.fromFloat(param[1] / this.gridScaleH, this.divide);
    var x = this.mouseToX(param[0], true);
    beat.push(x);
    return beat;
};

/**
 * 画布坐标映射到栅格坐标，假设栅格上摆满note时到最近note中心点
 * @param param
 */
GridUICatch.prototype.layerToGridOffset = function (param) {
    var beat = frac.fromFloat((param[1] - this.gridScaleH / this.divide / 2) / this.gridScaleH, this.divide);
    if (beat[0] < 0) {
        beat = [0, 0, 1];
    }
    var x = this.mouseToX(param[0]);
    beat.push(x);
    return beat;
};

/**
 * 画布坐标映射到栅格坐标，y轴不对齐（实际按1/288对齐）
 * @param param
 */
GridUICatch.prototype.layerToGridUnsnap = function (param) {
    var beat = frac.fromFloat(param[1] / this.gridScaleH, 288);
    var x = this.mouseToX(param[0]);
    beat.push(x);
    return beat;
};

/**
 * note对象转为4值数组
 */
GridUICatch.prototype.noteToParam = function (obj) {
    return [obj.beat[0], obj.beat[1], obj.beat[2], obj.x];
};

GridUICatch.prototype.paramToNote = function (param) {
    return {
        beat: [param[0], param[1], param[2]],
        x: param[3],
        tid: -1
    };
};

GridUICatch.prototype.showBlurMsg = function (msg) {
    $("#hold_hint").show().html(msg);
    setTimeout(function () {
        $("#hold_hint").fadeOut();
    }, 3000);
};

/**
 * 在复制之前完整的选择一个hold或者rain
 */
GridUICatch.prototype.onBeforeCopy = function () {
    var selected = this.note.children(".curr");
    var processed = {};
    for (var i = 0; i < selected.length; i++) {
        var note = $(selected[i]);
        var id = note.attr("data-tag");
        if (processed[id]) {
            continue;
        }
        if (note.hasClass("spinner_anchor") || note.hasClass("hold_node")) {
            var result = this.selectChainNotes(note);
            for (var j = 0; j < result.length; j++) {
                processed[result[j].id] = true;
            }
        }
    }
};

/**
 * 完整选择一个hold或者rain
 * @param div
 * @param noSelect 只返回结果不做选择效果
 */
GridUICatch.prototype.selectChainNotes = function (noteDiv, noSelect) {
    if(!noSelect){
        noteDiv.addClass("curr");
    }
    var id = noteDiv.attr("data-tag");
    var note = this.manager.getNote(id);
    var selectedNotes = [note];
    var curr = note;
    var tmpNote, tmpDiv;
    while (curr.prev > 0) {
        tmpNote = this.manager.getNote(curr.prev);
        tmpDiv = this.getNoteDiv(tmpNote.id);
        if(!noSelect){
            tmpDiv.addClass("curr");
        }
        selectedNotes.push(tmpNote);
        curr = tmpNote;
    }
    curr = note;
    while (curr.next > 0) {
        tmpNote = this.manager.getNote(curr.next);
        tmpDiv = this.getNoteDiv(tmpNote.id);
        if(!noSelect) {
            tmpDiv.addClass("curr");
        }
        selectedNotes.push(tmpNote);
        curr = tmpNote;
    }
    return selectedNotes;
};

/**
 * 通过加class的方式组选
 */
GridUICatch.prototype.clsChainSelect = function(noteDivs){
    var result = {};
    var divs = [];
    for (var i = 0; i < noteDivs.size(); i++) {
        result[noteDivs.eq(i).attr("data-tag")] = 1;
    }
    for (var i = 0; i < noteDivs.size(); i++) {
        var tmpArr = this.selectChainNotes(noteDivs.eq(i), true);
        for(var j=0;j<tmpArr.length;j++){
            result[tmpArr[j].id] = tmpArr[j];
        }
    }
    for(var k in result){
        this.note.children("[data-tag='" + k + "']").addClass("chain_select")
    }
};

module.exports = GridUICatch;